/*
 * VariableStringSerializer_test.cpp
 *
 *  Created on: Oct 23, 2012
 *      Author: m
 */

#include <memory>
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
#include <cstdlib>

#include "VariableStringSerializer.h"

#define _MIN_ARGS 3
#define _MODE_ARG 1
#define _INFILE_ARG 2
#define _OUTFILE_ARG 3
#define _SERIALIZE_MODE "-s"
#define _DESERIALIZE_MODE "-d"
#define _BIN_BUFFER_SIZE 256

typedef enum { serialize, deserialize, invalid } operation_mode_t;

void invalid_args()
{
    std::cerr << "Argumentos inválidos. " << std::endl
              <<"Uso: vss_ts [" << _SERIALIZE_MODE << "|" << _DESERIALIZE_MODE << "] input output"
              << std::endl;
    exit( 1 );
}

void invalid_mode()
{
    std::cerr << "Modo inválido. " << std::endl
              <<"Uso: vss_ts [" << _SERIALIZE_MODE << "|" << _DESERIALIZE_MODE << "] input output"
              << std::endl;
    exit( 2 );
}

operation_mode_t parse_mode( char* arg )
{
    if ( strcmp( arg, _SERIALIZE_MODE ) == 0 )
        return serialize;

    if ( strcmp( arg, _DESERIALIZE_MODE ) == 0 )
        return deserialize;

    return invalid;
}


int main( int argc, char* argv[] )
{
    std::fstream textFile;
    std::fstream binFile;
    std::shared_ptr< std::string > strBuffer;
    physical::byte binaryBuffer[_BIN_BUFFER_SIZE];
    physical::VariableStringSerializer stringSerializer;
    size_t serializationSize;
    physical::byte *bufferPtr;
    size_t bytesRead;
    size_t serializedBytes;
    size_t bytesDeserialized;

    if ( argc < _MIN_ARGS+1 )
        invalid_args();

    operation_mode_t mode = parse_mode( argv[_MODE_ARG] );

    switch ( mode )
    {
        case serialize:
            textFile.open( argv[_INFILE_ARG], std::ios_base::in );
            binFile.open( argv[_OUTFILE_ARG], std::ios_base::out | std::ios_base::trunc | std::ios_base::binary );


            strBuffer.reset( new std::string );
            while( getline( textFile, *strBuffer ) )
            {
                serializationSize = stringSerializer.serialize( strBuffer, binaryBuffer );
                binFile.write( binaryBuffer, serializationSize );
            }

            textFile.close();
            binFile.close();
            break;
            
        case deserialize:

            binFile.open( argv[_INFILE_ARG], std::ios_base::in | std::ios_base::binary );
            textFile.open( argv[_OUTFILE_ARG], std::ios_base::out | std::ios_base::trunc );

            bufferPtr = binaryBuffer;

            // Cargo el archivo completo en memoria
            binFile.read( binaryBuffer, _BIN_BUFFER_SIZE * 100 );
            bytesRead = binFile.gcount();
            serializedBytes = 0;

            while( serializedBytes < bytesRead  )
            {
                bytesDeserialized = stringSerializer.deserialize( bufferPtr, strBuffer );

                serializedBytes += bytesDeserialized;
                bufferPtr += bytesDeserialized;

                textFile << *strBuffer << std::endl;
            }

            textFile.close();
            binFile.close();

            break;
            
        case invalid:
            invalid_mode();
            break;
    }
    
    return 0;
}
